﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static ConsoleApp2.Program;

namespace ConsoleApp2
{
    internal class Program
    {
        //访问者模式：访问者主要解决数据和算法的耦合，尤其是在数据结构比较稳定，而算法多变的情况下。
        //为了不污染数据本身，访问者会将多种算法独立归类，并在访问数据时根据数据类型切换到对应的算法，实现数据的自由响应机制，并且确保算法的自由扩展。
        static void Main(string[] args)
        {

            //Shopping Cart购物车
            List<IAcceptable> shoppingCart=new List<IAcceptable>();
            shoppingCart.Add(new Candy("大白兔", new DateTime(2011, 12, 12), 10));
            shoppingCart.Add(new Candy("徐福记", new DateTime(2022, 12, 1), 20));
            shoppingCart.Add(new Candy("三只松鼠", new DateTime(2022, 6, 12), 10));
            shoppingCart.Add(new Fruit("苹果",new DateTime(2022,12,3), 10));
            shoppingCart.Add(new Wine("茅台", new DateTime(1995, 11, 3), 2000));

            DiscountVisitor discountVisitor = new DiscountVisitor(0.8);

            foreach (var item in shoppingCart)
            {
                item.Accept(discountVisitor);
            }
            Console.ReadKey();
        }

        #region 访问者模式在超时结算系统的应用
        #region 实现接待者接口的数据
        #region 接待者接口
        public interface IAcceptable
        { 
         bool Accept(Visitor visitor);
        }

        #endregion
        public abstract class Product:IAcceptable
        {
            /// <summary>
            /// 名字
            /// </summary>
            public string Name { get; set; }
            /// <summary>
            /// 生产日期
            /// </summary>
            public DateTime ProductDate { get; set; }
            /// <summary>
            /// 价格
            /// </summary>
            public double Price { set; get; }

            public Product(string name, DateTime productDate, int price)
            {
                this.Name = name;
                this.ProductDate = productDate;
                this.Price = price;
            }

            public abstract bool Accept(Visitor visitor);
        }
        /// <summary>
        /// 糖果类
        /// </summary>
        public class Candy : Product
        {
            public Candy(string name, DateTime productDate, int price) : base(name, productDate, price)
            {
            }

           public override bool Accept(Visitor visitor)
            {
                return visitor.Visit(this);
            }
        }
        /// <summary>
        /// 酒类
        /// </summary>
        public  class  Wine : Product
        {
            public Wine(string name, DateTime productDate, int price) : base(name, productDate, price)
            {
            }

            public override bool Accept(Visitor visitor)
            {
               return visitor.Visit(this);
            }
        }
        /// <summary>
        /// 水果类
        /// </summary>
        public class Fruit : Product
        {
            public Fruit(string name, DateTime productDate, int price) : base(name, productDate, price)
            {
            }
            /// <summary>
            /// 重量
            /// </summary>
            public float Weight { set; get; }

            public override bool Accept(Visitor visitor)
            {
                return visitor.Visit(this);    
            }
        }

        #endregion

        #region 实现访问不同数据方法的访问者
        public interface Visitor
        {
            bool Visit<T>(T product) where T:Product;
        }

        public class DiscountVisitor : Visitor
        {
            public double Discount { get; set; }
            public DiscountVisitor(double discount)
            {
                this.Discount = discount;
            }
            public bool Visit<T>(T product) where T:Product
            {
                double discountPrice = this.Discount * product.Price;
                Console.WriteLine(product.Name + "打6折，打折后价格为" + discountPrice);
                return true;
            }
        }
        #endregion 
        #endregion

        //访问者模式成功将数据资源(需要实现接待者接口)与数据算法(需要实现访问者接口)分离开来。重载方法的使用让多样的算法自成体系，多态化的访问者接口保证了系统算法的可扩展性，
        //而数据保持相对固定，最终形成一个算法类型类对应一套数据。
        //利用双派发确保了访问者对泛型数据元素的识别与算法匹配，使数据集合的迭代与数据元素的自动分拣成为可能。
        //双派发：接待者将访问者"派发"到自己的接待方法中，然后再将自己"派发"给访问者，告知自己的身份，然后访问者根据接待者的信息对接待者进行访问。
        //访问模式的核心在于对重载方法与双派发方式的利用，这是实现数据算法自动响应机制的关键所在。
    }
}
